package com.web.controller;

import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.web.util.util;
import com.web.wrapper.CephAccessorFactory;
import com.web.wrapper.RbdParameter;
import com.web.wrapper.hood.CephRBDAccessor;

@Controller
@RequestMapping("rbd")
public class CephWebController {
	private Logger log = Logger.getLogger(getClass()) ;
	
	/**
	 * for testing
	 */
	@RequestMapping("hello")
	@ResponseBody
	public String hello(){
		HashMap<String,String> map = Maps.newHashMap() ;
		map.put("1",	"one" ) ;
		map.put("2",	"two" ) ;
		map.put("3",	"three" ) ;
		return JSONObject.toJSONString( map ) ;
	}
	
	/**
	 * create pool
	 * @throws Exception 
	 */
	@RequestMapping(value="create",method={RequestMethod.POST})
	@ResponseBody
	public String createPool(@RequestBody String body,HttpServletRequest request,HttpServletResponse response) throws Exception{
		RbdParameter param = initParam(body,request ) ;
		String message = param.getPool(true) + " created" ;
		int code = util.SUCCESS ;
		log.debug( "body="+body );
		try {
			CephRBDAccessor accessor = CephAccessorFactory.getRbd(param.getSessionid(),param.getPool(true)) ;
			accessor.createPool( request.getServletContext() );
		} catch (Exception e) {
			if( e instanceof NullPointerException){
				message = "No pool specified " ;
			}else{
				message = e.getMessage() ;
			}
			code = util.FAIL ;
			log.error("Can not create the pool of "+param.getPool(true),e);
		}
		return util.formatReturn( code , message).toJSONString() ; 
	}
	
	/**
	 * list pool
	 * @throws Exception 
	 */
	@RequestMapping(value={"listPool"}, method={org.springframework.web.bind.annotation.RequestMethod.GET})
	@ResponseBody
	public String listPools(HttpServletRequest request, HttpServletResponse response) throws Exception {
		RbdParameter param = initParam(null, request);
		this.log.debug("body:" + JSONObject.toJSONString(param));
		String sessionId = "anonymous";
		String pool = "rbd";
		String message = "can not get the pools ";
		String[] pools = new String[0];
		try {
    	    		CephRBDAccessor accessor = CephAccessorFactory.getRbd(sessionId, pool);
	    		accessor.connect(request.getServletContext());
	    		pools = accessor.listPool(request.getServletContext());
	    } catch (Exception e) {
	    		this.log.error("Can not list pools " + util.cephErrMsg(e), e);
	    		if (!StringUtils.isEmpty(e.getMessage())) {
	    			message = e.getMessage();
	    		}
	    		return util.formatReturn(util.FAIL, message).toJSONString();
	    }
	    message = "all pools listed";
	    if (this.log.isDebugEnabled()) {
	      this.log.debug(util.formatReturn(util.SUCCESS, message).toJSONString());
	    }
	    return util.formatReturn(util.SUCCESS, message, pools).toJSONString();
	}
	
	/**
	 * delete pool
	 * @throws Exception 
	 */
	@RequestMapping(value="delete",method={RequestMethod.POST})
	@ResponseBody
	public String removePool( @RequestBody String body,HttpServletRequest request,HttpServletResponse response) throws Exception{
		RbdParameter param = initParam(body,request ) ;
		String message = param.getPool(true) + " deleted" ;
		int code = util.SUCCESS ;
		log.debug( "body="+body );
		try {
			CephRBDAccessor accessor = CephAccessorFactory.getRbd(param.getSessionid(),param.getPool(true)) ;
			accessor.removePool( request.getServletContext() );
		} catch (Exception e) {
			if( e instanceof NullPointerException){
				message = "No pool specified " ;
			}else{
				message = e.getMessage() ;
			}
			code = util.FAIL ;
			log.error("Can not delete the pool of "+param.getPool(true),e);
		}
		return util.formatReturn( code , message).toJSONString() ; 
	}
	 
	/**
	 * create a image in the pool,if pool didn't exist the create it
	 * @throws Exception 
	 */
	@RequestMapping(value="createImg",method={RequestMethod.POST})
	@ResponseBody
	public String createImage(@RequestBody String body,HttpServletRequest request,HttpServletResponse response) throws Exception{
		RbdParameter param = initParam(body,request ) ;
		log.debug("body:"+JSONObject.toJSONString( param));
		String sessionId = param.getSessionid() ;//user session
		String pool = param.getPool(true) ;     //the namespace in k8s
		String imageName = param.getImageName(true);
		long sizeOfImg = param.getSize() ;
		String message = "can not get the pool "+pool ;
		
		try {
			CephRBDAccessor accessor = CephAccessorFactory.getRbd(sessionId,pool) ;
			accessor.connect( request.getServletContext());
			accessor.createImg( imageName,  sizeOfImg );
		} catch (Exception e) {
			log.error("Can not connect to the Ceph cluster",e); 
			if( !StringUtils.isEmpty( e.getMessage() )){
				message = e.getMessage() ;
			}
			return util.formatReturn(util.FAIL, message).toJSONString() ;
		}finally{
//			log.warn("If there will be io connection leak or someting about ioctx problem,then try  release "
//					+ "the io here manually");
//			if( null != accessor ){
//			    ioctx will be released when it was evicted in the RbdRemovalListerner
//				accessor.release(); 
//			}
		}
		
		message = imageName+" created" ;
		if( log.isDebugEnabled() ){
			log.debug( util.formatReturn(util.SUCCESS, message).toJSONString() );
		}
		return util.formatReturn(util.SUCCESS, message).toJSONString() ; 
	}
	
	/**
	 * list images in the pool,if pool didn't exist the create it
	 * @throws Exception 
	 */
	@RequestMapping(value={"listImg"}, method={org.springframework.web.bind.annotation.RequestMethod.GET})
	@ResponseBody
	public String listImages(HttpServletRequest request, HttpServletResponse response) throws Exception
	{
		RbdParameter param = initParam(null, request);
	    this.log.debug("body:" + JSONObject.toJSONString(param));
	    String sessionId = param.getSessionid();
	    String pool = param.getPool(true);
	    String message = "can not get the images under the " + pool;
	    String[] images = new String[0];
	    try {
	    		CephRBDAccessor accessor = CephAccessorFactory.getRbd(sessionId, pool);
	    		accessor.connect(request.getServletContext());
	    		images = accessor.listImg();
	    } catch (Exception e) {
	    		this.log.error("Can not connect to the Ceph cluster " + util.cephErrMsg(e), e);
	    		if (!StringUtils.isEmpty(e.getMessage())) {
	    			message = e.getMessage();
	    		}
	    		return util.formatReturn(util.FAIL, message).toJSONString();
	    	} finally {
	    	
	    }
	    message = pool + " listed";
	    // Log the return message
	    if (log.isDebugEnabled()) {
	    		this.log.debug(util.formatReturn(util.SUCCESS, message, images).toJSONString()); 
	    }
	    return util.formatReturn(util.SUCCESS, message, images).toJSONString();
	}
	
	/**
	 * remove a image in the pool,if pool didn't exist the create it
	 * @throws Exception 
	 */
	@RequestMapping(value="removeImg",method={RequestMethod.POST})
	@ResponseBody
	public String  removeImage(@RequestBody String body,HttpServletRequest request,HttpServletResponse response) throws Exception{
		RbdParameter param = initParam(body,request ) ;
		log.debug("body:"+JSONObject.toJSONString( param));
		String sessionId = param.getSessionid() ;//user session
		String pool = param.getPool(true) ;     //the namespace in k8s
		String imageName = param.getImageName(true);
		String message = "can not get the pool "+pool ;
		//String res;
		try {
			CephRBDAccessor accessor = CephAccessorFactory.getRbd(sessionId,pool) ;
			accessor.connect( request.getServletContext());
			message = accessor.deleteImg(pool, imageName);
		} catch (Exception e) {
			log.error("Can not connect to the Ceph cluster",e); 
			if( !StringUtils.isEmpty( e.getMessage() )){
				message = e.getMessage() ;
			}
			return util.formatReturn(util.FAIL, message).toJSONString() ;
		}finally{
//			log.warn("If there will be io connection leak or someting about ioctx problem,then try  release "
//					+ "the io here manually");
//			if( null != accessor ){
//			    ioctx will be released when it was evicted in the RbdRemovalListerner
//				accessor.release(); 
//			}
		}
		
		if (message == "success") {
			message = imageName+" deleted" ;
			if( log.isDebugEnabled() ){
				log.debug( util.formatReturn(util.SUCCESS, message).toJSONString() );
			}
			return util.formatReturn(util.SUCCESS, message).toJSONString() ;
		}
		
		return util.formatReturn(util.FAIL, message).toJSONString() ; 
	}
	
	/**
	 * To get the real size used by a rbd image
	 * @throws Exception 
	 */
	@RequestMapping(value={"getImgUsage"}, method={org.springframework.web.bind.annotation.RequestMethod.GET})
	@ResponseBody
	public String getImgusage(HttpServletRequest request, HttpServletResponse response) throws Exception
	{
		RbdParameter param = initParam(null, request);
	    this.log.debug("body:" + JSONObject.toJSONString(param));
	    String sessionId = param.getSessionid() ;//user session
		String pool = param.getPool(true) ;     //the namespace in k8s
		String imageName = param.getImageName(true);
	    String message = "Can not get the usage-info of "+pool+"/"+imageName;
	    String usageInfo ;
	    try {
	    		CephRBDAccessor accessor = CephAccessorFactory.getRbd(sessionId, pool);
	    		accessor.connect(request.getServletContext());
	    		usageInfo = accessor.usedImg(pool,imageName);
	    } catch (Exception e) {
	    		this.log.error("Can not connect to the Ceph cluster " + util.cephErrMsg(e), e);
	    		if (!StringUtils.isEmpty(e.getMessage())) {
	    			message = e.getMessage();
	    		}
	    		return util.formatReturn(util.FAIL, message).toJSONString();
	    } finally {
	    
	    }
	    message = imageName + "'s usage-Info shown";
	    if (this.log.isDebugEnabled()) {
	    		this.log.debug(util.formatReturn(util.SUCCESS, message, usageInfo).toJSONString()); 
	    }
	    return util.formatReturn(util.SUCCESS, message, usageInfo).toJSONString(); 
	 }
	
	@RequestMapping(value={"checkImgStatus"}, method={org.springframework.web.bind.annotation.RequestMethod.GET})
	@ResponseBody
	public String checkImgStatus(String body, HttpServletRequest request, HttpServletResponse response) throws Exception
	{
		RbdParameter param = initParam(null, request);
	    this.log.debug("body:" + JSONObject.toJSONString(param));
	    String sessionId = param.getSessionid();
	    String pool = param.getPool(true);
	    String imageName = param.getImageName(true);
	    String message = "can not get the images under the " + pool;
	    boolean exist = false;
	    try
	    {
	    		CephRBDAccessor accessor = CephAccessorFactory.getRbd(sessionId, pool);
	    		accessor.connect(request.getServletContext());
	    		exist = accessor.isImageExisting(imageName);
	    } catch (Exception e) {
	    		this.log.error("Can not check image status " + util.cephErrMsg(e), e);
	    		if (!StringUtils.isEmpty(e.getMessage())) {
	    			message = "No such image in pool " + pool + "," + e.getMessage();
	    		}
	    		return util.formatReturn(util.FAIL, message).toJSONString();
	    }

	    message = imageName + " exist";
	    if (this.log.isDebugEnabled()) {
	    		this.log.debug(util.formatReturn(util.SUCCESS, message).toJSONString());
	    }
	    return util.formatReturn(util.SUCCESS, message, Boolean.valueOf(exist)).toJSONString();
	}
	
	public void renameImage(){
		//TODO
	}
	
	/**
	 * get the param form request
	 * @throws Exception 
	 */
	private RbdParameter initParam(String body,HttpServletRequest request) throws Exception{
		RbdParameter param = util.fromJson(body, RbdParameter.class) ;
		if( null == param || StringUtils.isEmpty( param.getPool(true))){
			param = extractParam( request ) ;
		}
		return param ;
	}
	/**
	 *  
	 */
    private RbdParameter extractParam(HttpServletRequest request){
    		RbdParameter p = new RbdParameter() ;
    		if( null == request ) 
    			return p ;
    		p.setPool( util.getParam(request, "pool" ) );
    		p.setImageName( util.getParamIgrCase(request, "imageName" )  ); 
    		p.setSessionid( util.getParam(request, "sessionid" ));
    		p.setSize( util.getLongParam(request, "size" ) );
    		return p ;
    }
    
    /**
	 * To check the health-status of ceph
	 * @throws Exception 
	 */
	@RequestMapping(value={"getCephHealth"}, method={org.springframework.web.bind.annotation.RequestMethod.GET})
	@ResponseBody
	public String getCephHealth(HttpServletRequest request, HttpServletResponse response) throws Exception
	{
		RbdParameter param = initParam(null, request);
	    this.log.debug("body:" + JSONObject.toJSONString(param));
	    String message = "Can't get the ceph health status!";
	    String sessionId = param.getSessionid() ;//user session
		String pool = param.getPool(true) ;     //the namespace in k8s
	    String healthInfo ;
	    try {
	    		//healthInfo = new CephRBDAccessor().cephHealth();
	    		CephRBDAccessor accessor = CephAccessorFactory.getRbd(sessionId, pool);
	    		accessor.connect(request.getServletContext());
	    		healthInfo = accessor.cephHealth();
	    } catch (Exception e) {
	    		this.log.error("Can not connect to the Ceph cluster " + util.cephErrMsg(e), e);
	    		if (!StringUtils.isEmpty(e.getMessage())) {
	    			message = e.getMessage();
	    		}
	    		return util.formatReturn(util.FAIL, message).toJSONString();
	    } finally {
	    
	    }
	    message = "the ceph health status has showed";
	    if (this.log.isDebugEnabled()) {
	    		this.log.debug(util.formatReturn(util.SUCCESS, message, healthInfo).toJSONString()); 
	    }
	    return util.formatReturn(util.SUCCESS, message, healthInfo).toJSONString(); 
	 }
	
	
	/**
     * To resize  a rbd image
     * @throws Exception 
     */
	@RequestMapping(value="resizeImg",method={RequestMethod.POST})
	@ResponseBody
	public String resizeImage(@RequestBody String body,HttpServletRequest request,HttpServletResponse response) throws Exception{
		RbdParameter param = initParam(body,request ) ;
		log.debug("body:"+JSONObject.toJSONString( param));
		String sessionId = param.getSessionid() ;//user session
		String pool = param.getPool(true) ;     //the namespace in k8s
		String imageName = param.getImageName(true);
		long sizeOfImg = param.getSize() ;
		String message = "can not get the pool "+pool ;
		
		try {
			CephRBDAccessor accessor = CephAccessorFactory.getRbd(sessionId,pool) ;
			accessor.connect( request.getServletContext());
			accessor.resize(pool,imageName,sizeOfImg);
		} catch (Exception e) {
			log.error("Can not connect to the Ceph cluster",e); 
			if( !StringUtils.isEmpty( e.getMessage() )){
				message = e.getMessage() ;
			}
			return util.formatReturn(util.FAIL, message).toJSONString() ;
		}finally{
		}
		
		message = imageName+" resized" ;
		if( log.isDebugEnabled() ){
			log.debug( util.formatReturn(util.SUCCESS, message).toJSONString() );
		}
		return util.formatReturn(util.SUCCESS, message).toJSONString() ; 
	}
	
	/**
     * To resize  mount dir
     * @throws Exception 
     */
	@RequestMapping(value="resizeDir",method={RequestMethod.POST})
	@ResponseBody
	public String resizeDir(@RequestBody String body,HttpServletRequest request,HttpServletResponse response) throws Exception{
		RbdParameter param = initParam(body,request ) ;
		log.debug("body:"+JSONObject.toJSONString( param));
		String sessionId = param.getSessionid() ;//user session
		String pool = param.getPool(true) ;     //the namespace in k8s
		String imageName = param.getImageName(true);
		String message = "can not get the pool "+pool ;
		
		try {
			CephRBDAccessor accessor = CephAccessorFactory.getRbd(sessionId,pool) ;
			accessor.connect( request.getServletContext());
			accessor.resizeDir(pool,imageName);
		} catch (Exception e) {
			log.error("Can not connect to the Ceph cluster",e); 
			if( !StringUtils.isEmpty( e.getMessage() )){
				message = e.getMessage() ;
			}
			return util.formatReturn(util.FAIL, message).toJSONString() ;
		}finally{
		}
		
		message = imageName+"'s mount dir had been resized" ;
		if( log.isDebugEnabled() ){
			log.debug( util.formatReturn(util.SUCCESS, message).toJSONString() );
		}
		return util.formatReturn(util.SUCCESS, message).toJSONString() ; 
	}
	
}
